﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.IO;
using System.Xml;

namespace WpfApplication1
{
    class ClosableTabItem : TabItem
    {
        public string Title
        {
            set
            {
                ((CloseableHeader)this.Header).FileName.Content = value;
            }
            get
            {
                return ((CloseableHeader)this.Header).FileName.Content.ToString();
            }
        }

        FrameworkElement selectedVisual;
        Frame bBox;
        List<Canvas> layers = new List<Canvas>();
        int selectedLayer = -1;

        public List<Canvas> Layers { get { return layers; } }
        public int SelectedLayer { set { selectedLayer = value; } get { return selectedLayer; } }

        public ClosableTabItem()
        {
            CloseableHeader closableTabHeader = new CloseableHeader();
            closableTabHeader.close_button.Click += new System.Windows.RoutedEventHandler(close_button_Click);
            this.Header = closableTabHeader;
        }

        public ClosableTabItem(string title)
        {
            CloseableHeader closableTabHeader = new CloseableHeader();
            closableTabHeader.FileName.Content = title;
            closableTabHeader.close_button.Click += new System.Windows.RoutedEventHandler(close_button_Click);
            this.Header = closableTabHeader;
            ScrollViewer sv = new ScrollViewer();
            sv.Loaded += new RoutedEventHandler(sv_Loaded);
            Canvas svContent = new Canvas();
            svContent.Background = Brushes.DarkGray;
            sv.Content = svContent;
            Canvas viewPort = new Canvas();
            viewPort.Background = Brushes.White;
            svContent.Children.Add(viewPort);
            this.Content = sv;
        }

        public ClosableTabItem(string title, FrameworkElement image)
        {
            CloseableHeader closableTabHeader = new CloseableHeader();
            closableTabHeader.FileName.Content = title;
            closableTabHeader.close_button.Click += new System.Windows.RoutedEventHandler(close_button_Click);
            this.Header = closableTabHeader;
            ScrollViewer sv = new ScrollViewer();
            sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
            sv.Loaded += new RoutedEventHandler(sv_Loaded);
            Canvas svContent = new Canvas();
            svContent.Background = Brushes.DarkGray;
            //svContent.MouseWheel += new MouseWheelEventHandler(sv_MouseWheel);
            sv.Content = svContent;
            Canvas viewPort = new Canvas();
            viewPort.Background = Brushes.White;
            viewPort.ClipToBounds = true;
            viewPort.MouseDown += new MouseButtonEventHandler(SelectItem);
            viewPort.LayoutTransform = newTransformations();
            viewPort.Children.Add(image);
            Canvas.SetTop(image, 0);
            Canvas.SetLeft(image, 0);
            image.Loaded += new RoutedEventHandler(image_Loaded);
            svContent.Children.Add(viewPort);
            this.Content = sv;
        }

        Canvas newLayer(bool isFirst)
        {
            Canvas newLayer;
            if (isFirst)
            {
                string canvasXaml = XamlWriter.Save(getImageViewport());
                StringReader stringReader = new StringReader(canvasXaml);
                XmlReader xmlReader = XmlReader.Create(stringReader);
                newLayer = (Canvas)XamlReader.Load(xmlReader);
            }
            else
            {
                newLayer = new Canvas();
                newLayer.Height = getImageViewport().Height;
                newLayer.Width = getImageViewport().Width;
                newLayer.LayoutTransform = newTransformations();
            }
            layers.Add(newLayer);
            selectedLayer = layers.Count - 1;
            return new Canvas();
        }

        public TransformGroup newTransformations()
        {
            TransformGroup tg = new TransformGroup();
            ScaleTransform st = new ScaleTransform();
            RotateTransform rt = new RotateTransform();
            TranslateTransform tt = new TranslateTransform();
            SkewTransform sKt = new SkewTransform();
            tg.Children.Add(st);
            tg.Children.Add(rt);
            tg.Children.Add(tt);
            tg.Children.Add(sKt);
            return tg;
        }

        void sv_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.Z))
            {
                Canvas imageCanvas = getImageViewport();
                Canvas svCanvas = getScrollViewerViewport();
                ScaleTransform renderScaleTransform = (ScaleTransform)svCanvas.RenderTransform;
                ScaleTransform layoutScaleTransform = (ScaleTransform)svCanvas.LayoutTransform;
                bool notCrossingWidth = imageCanvas.Width * (renderScaleTransform.ScaleX + e.Delta * 0.001) <= getScrollViewer().ViewportWidth &&
                    Canvas.GetLeft(imageCanvas) * (renderScaleTransform.ScaleX + e.Delta * 0.001) >= 0;
                bool notCrossingHeight = imageCanvas.Height * (renderScaleTransform.ScaleX + e.Delta * 0.001) <= getScrollViewer().ViewportHeight &&
                    Canvas.GetTop(imageCanvas) * (renderScaleTransform.ScaleX + e.Delta * 0.001) >= 0;
                if (renderScaleTransform.ScaleX + e.Delta * 0.001 > 0)
                {
                    if (notCrossingHeight && notCrossingWidth)
                    {
                        //scaleTransform.CenterX = svCanvas.ActualWidth / 2;
                        //scaleTransform.CenterY = svCanvas.ActualHeight / 2;
                        renderScaleTransform.ScaleX += e.Delta * 0.001;
                        renderScaleTransform.ScaleY += e.Delta * 0.001;
                        //double top = (svCanvas.Height - imageCanvas.Height * (scaleTransform.ScaleY + e.Delta * 0.0001)) / 2;
                        //double left = (svCanvas.Width - imageCanvas.Width * (scaleTransform.ScaleX + e.Delta * 0.0001)) / 2;
                        //Canvas.SetTop(imageCanvas, top);
                        //Canvas.SetLeft(imageCanvas, left); 
                    }
                    else
                    {
                        layoutScaleTransform.ScaleX += e.Delta * 0.001;
                        layoutScaleTransform.ScaleY += e.Delta * 0.001;
                    }
                }

                //if (imageCanvas.Width * (renderScaleTransform.ScaleX + e.Delta * 0.001) >= getScrollViewer().ViewportWidth)
                //{
                //    svCanvas.Width = imageCanvas.Width * (renderScaleTransform.ScaleX + e.Delta * 0.001);
                //}
                //if (imageCanvas.Height * (renderScaleTransform.ScaleY + e.Delta * 0.001) >= getScrollViewer().ViewportHeight)
                //{
                //    svCanvas.Height = imageCanvas.Height * (renderScaleTransform.ScaleY + e.Delta * 0.001);
                //}

                
            }
        }

        void image_Loaded(object sender, RoutedEventArgs e)
        {

            try
            {
                Canvas imageViewPort = getImageViewport();
                Canvas scrollViewerViewport = getScrollViewerViewport();
                Image i = (Image)sender;
                ScaleTransform st = (ScaleTransform)((TransformGroup)imageViewPort.LayoutTransform).Children[0];
                i.Height = i.Source.Height;
                i.Width = i.Source.Width;
                imageViewPort.Height = i.Source.Height;
                imageViewPort.Width = i.Source.Width;
                double ratio = (scrollViewerViewport.Height * 0.8) / imageViewPort.Height
                    < (scrollViewerViewport.Width * 0.8) / imageViewPort.Width ?
                    (scrollViewerViewport.Height * 0.8) / imageViewPort.Height :
                    (scrollViewerViewport.Width * 0.8) / imageViewPort.Width;
                if (ratio < 1)
                {
                    st.ScaleX = ratio;
                    st.ScaleY = ratio;
                    st.CenterX = imageViewPort.Width / 2;
                    st.CenterY = imageViewPort.Height / 2;
                }
                else
                {
                    st.ScaleX = 1;
                    st.ScaleY = 1;
                    st.CenterX = imageViewPort.Width / 2;
                    st.CenterY = imageViewPort.Height / 2;
                }
                double top = (scrollViewerViewport.Height - imageViewPort.Height * st.ScaleY) / 2;
                double left = (scrollViewerViewport.Width - imageViewPort.Width * st.ScaleX) / 2;
                Canvas.SetTop(imageViewPort, top);
                Canvas.SetLeft(imageViewPort, left);

                if (Layers.Count == 0)
                {
                    newLayer(true);
                }
            }
            catch { }
        }

        public ScrollViewer getScrollViewer()
        {
            return (ScrollViewer)this.Content;
        }

        public Canvas getScrollViewerViewport()
        {
            return (Canvas)((ScrollViewer)this.Content).Content;
        }

        public Canvas getImageViewport()
        {
            return (Canvas)((Canvas)((ScrollViewer)this.Content).Content).Children[0];
        }

        void sv_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                ScrollViewer sv = getScrollViewer();
                Canvas svContent = getScrollViewerViewport();
                svContent.Height = sv.ViewportHeight;
                svContent.Width = sv.ViewportWidth;
            }
            catch { }
        }

        public ScrollViewer getTabContent()
        {
            return (ScrollViewer)this.Content;
        }

        /*
         *pass all childrens to draw them on the canvas 
         */
        public void AddVisual(FrameworkElement newVisual)
        {
            getImageViewport().Children.Add(newVisual);
        }
        public void AddVisualToLayer(FrameworkElement newVisual)
        {
            layers[selectedLayer].Children.Add(newVisual);
        }

        #region get last child(layer) and then change added layer opacity and color
        /************************************************************************/
        /************************************************************************/
        object lastObj;
        public void SetLastChild(object obj)
        {
            lastObj = obj;
        }
        /************************************************************************/
        public void ChangeOpacity(double opacity)
        {
            Console.WriteLine(opacity);
            ((Rectangle)getImageViewport().Children[getImageViewport().Children.IndexOf((UIElement)lastObj)]).Opacity = opacity;
        }
        /************************************************************************/
        public void ChangeLayerRectangleColor(Color color)
        {
            ((Rectangle)getImageViewport().Children[getImageViewport().Children.IndexOf((UIElement)lastObj)]).Fill = new SolidColorBrush(color);
        }
        /************************************************************************/
        /************************************************************************/
        #endregion

        void close_button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            ((TabControl)this.Parent).Items.Remove(this);
        }

        private void SelectItem(object sender, MouseButtonEventArgs e)
        {
            try
            {
                // Retrieve the coordinate of the mouse position.
                Point pt = e.GetPosition((Canvas)sender);

                // Clear the contents of the list used for hit test results.
                //((Canvas)sender).Children.Remove(selectedVisual);

                // Set up a callback to receive the hit test result enumeration.
                VisualTreeHelper.HitTest((Canvas)sender, null,
                    new HitTestResultCallback(MyHitTestResult),
                    new PointHitTestParameters(pt));
                // Perform actions on the hit test results list. 
                //if (hitResultsList.Count > 0)
                //{
                //    Console.WriteLine("Number of Visuals Hit: " + hitResultsList.Count);
                //}
            }
            catch { }
        }


        // Return the result of the hit test to the callback. 
        public HitTestResultBehavior MyHitTestResult(HitTestResult result)
        {
            getScrollViewerViewport().Children.Remove(bBox);
            // Add the hit test result to the list that will be processed after the enumeration.
            if (result.VisualHit != getImageViewport())
            {
                selectedVisual = (FrameworkElement)result.VisualHit; 
            }
            try
            {
                Rect bounds = selectedVisual.TransformToVisual((Canvas)selectedVisual.Parent).TransformBounds(new Rect(selectedVisual.RenderSize));
                ScaleTransform viewportScale = (ScaleTransform)((TransformGroup)getImageViewport().LayoutTransform).Children[0];
                bBox = new Frame(bounds.Height * viewportScale.ScaleY,
                    bounds.Width * viewportScale.ScaleX, selectedVisual);
                //bBox.ClipToBounds = false;
                getScrollViewerViewport().Children.Add(bBox);
                Canvas.SetLeft(bBox, Canvas.GetLeft(getImageViewport()) + Canvas.GetLeft(selectedVisual) * viewportScale.ScaleX - 5);
                Canvas.SetTop(bBox, Canvas.GetTop(getImageViewport()) + Canvas.GetTop(selectedVisual) * viewportScale.ScaleY - 5);
            }
            catch { }

            // Set the behavior to return visuals at all z-order levels. 
            return HitTestResultBehavior.Stop;
        }
    }
}
